package com.hospital.register.cmn.service.impl;

import com.hospital.register.cmn.mapper.DictMapper;
import com.hospital.register.cmn.service.DictService;
import com.hospital.register.common.exception.BusinessException;
import com.hospital.register.common.result.ResultCodeEnum;
import com.hospital.register.dto.cmn.DictExcelDto;
import com.hospital.register.dto.cmn.DictNameQueryDto;
import com.hospital.register.model.cmn.Dict;
import com.hospital.register.validation.groups.InsertValidation;
import com.hospital.register.vo.cmn.DictChildVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;

@Service
public class DictServiceImpl implements DictService {

    /**
     * 访问字典数据
     */
    @Autowired
    private DictMapper dictMapper;

    /**
     * 注入 Spring 提供的校验器
     */
    @Autowired
    private Validator validator;

    @Override
    @Transactional(timeout = 5, readOnly = true)
    @Cacheable(value = "dict", keyGenerator = "keyGenerator")
    public List<DictChildVo> selectByParentId(Long parentId) {
        return this.dictMapper.selectByParentId(parentId);

    }

    @Override
    @Async
    @Transactional(readOnly = true, timeout = 1)
    public Future<Boolean> hasChildren(DictChildVo dict) {
        Integer count = this.dictMapper.countByParentId(dict.getId());
        dict.setHasChildren(count != null && count > 0);
        return new AsyncResult<>(true);
    }

    @Override
    @Cacheable(value = "dict", keyGenerator = "keyGenerator")
    @Transactional(timeout = 5, readOnly = true)
    public List<DictChildVo> selectChildrenByCode(String dictCode) {
        Long parentId = this.dictMapper.selectIdByCode(dictCode);

        if (parentId != null) {
            return this.selectByParentId(parentId);
        } else {
            return Collections.emptyList();
        }
    }

    @Override
    @CacheEvict(value = "dict", allEntries = true)
    @Transactional(timeout = 5)
    public int insertList(List<Dict> dictList) {
        return this.dictMapper.insertList(dictList);
    }

    @Override
    @Transactional(readOnly = true, timeout = 5)
    public List<DictExcelDto> selectExcelData() {
        return this.dictMapper.selectExcelData();
    }

    @Override
    @CacheEvict(value = "dict", allEntries = true)
    @Transactional(timeout = 3)
    public int deleteList(List<Long> idList) {
        return this.dictMapper.deleteList(idList);
    }

    @Override
    @Transactional(readOnly = true, timeout = 1)
    public boolean existAny(Collection<Long> idCollection) {
        Integer count = this.dictMapper.countByIdCollection(idCollection);
        return count != null && count > 0;
    }

    @Override
    @Transactional(readOnly = true, timeout = 1)
    public boolean existAll(Collection<Long> idCollection) {
        Integer count = this.dictMapper.countByIdCollection(idCollection);
        return count != null && count.equals(idCollection.size());
    }

    @Override
    public void violatedConstraints(DictExcelDto dict, int index) throws BusinessException {
        if (dict == null) {
            throw new BusinessException("解析第" + index + "行时出错，这是一个空字典", ResultCodeEnum.PARAM_ERROR.getCode());
        }

        if (dict.getId().equals(dict.getParentId())) {//id 和父 id 相同
            throw new BusinessException("解析第" + index + "行时出错，id 与父 id 相同", ResultCodeEnum.PARAM_ERROR.getCode());
        }

        Set<ConstraintViolation<DictExcelDto>> violationSet = this.validator.validate(dict, InsertValidation.class);//该字典的校验结果

        if (violationSet.size() > 0) {//有错误
            for (ConstraintViolation<DictExcelDto> violation : violationSet) {
                throw new BusinessException("解析第" + index + "行数据时出错，" + violation.getMessage(), ResultCodeEnum.PARAM_ERROR.getCode());
            }
        }

    }

    @Override
    public String selectName(DictNameQueryDto dto) {
        if (dto.getDictCode() != null && dto.getDictCode().length() > 0) {//有提供编码
            Long parentId = this.dictMapper.selectIdByCode(dto.getDictCode());
            dto.setParentId(parentId);
        }
        return this.dictMapper.selectName(dto);
    }

}
